// object 是表示一个js对象
/* let a: object;
a = function (){};
a = {};
// 因为万物皆是对象，所以所有的值都是可以写object。  一般不用这个object，和没写差不多。 */

/* 
let a: {name:string}; // 这种就是必须传入一个对象，里面要有name属性，值是字符串。 如果是
a = {}; // 这种时候会报错，必须要有个name属性，并且是字符串。 
*/

/* 
let a: {name? : string};
a = {}; // 加一个问号，是可选属性。 不写也行 
*/

/* 
let a:{name: '猪八戒'| '沙僧'} // 某个属性只能二选一
a = {
    name : '沙僧'
} 
    */

/* 
// 必须有一个属性，并且是name。 不能有其他属性。
let a :{name:string}
a = {sex:1} 
*/

// 任意属性，并且是任意个数。
/* let a:{
    name:string,
    [key:string]:any, // key值是字符串，值是任意值。 并且是任意个数。
}
a = {
    name: '1',
    sldfkjewr:333, // 这个就是key值，
    sldfjkser:444
} */

// 设定函数的方式
// let a:Function; // 这个方式不行
/* let a : (p1: number,p2:number)=>number;
// a = (p1,p2)=>{ // 这个方式就设定进入值和返回值
//     return p1 + p2;
// }
// a('4','5') // 这里会有提示，说不允许string类型赋值给number
a = ()=>{ 
    // 参数问题：// 这样也是合法，但是不建议这样写。 因为传入的值没有被使用，所以ts就没对传入参数进行校验。 而返回值因为有值且符合number，就校验通过了
    return 1;
} */



// 数组
/* let a: number[]; // 方式1
a = [1,2]

let b: Array<string>; // 方式2
b = ['1','2']

// 数组 - 联合类型
let c: number[] | string[];
c = [1,2] */




// 元祖 - 固定长度的数组, 就是java里的list, 而ArrayList是不固定长度,才等同于前端array.
/*     let a:[string,string];
    a = ['h','3']// 没问题
    a = ['1','2','3'] // 需要两个,不能多个或者少于2个. */

// 多个元祖 : 第一个是字符串,后面是多个数字
// let tuple1: [string,...number[]];
// tuple1 = ['11',1]


// 枚举 - 感觉就是常量的变化写法  全都是java的东西
/* enum ENUM_SEX {
    MALE = 1, // 指定值枚举
    FEMALE = 0
}

let a : {
    sex: ENUM_SEX.FEMALE | ENUM_SEX.MALE
}

a = {
    sex: 1
}
console.log(a,'90')

// 枚举 - 不指定值,会自动增长
enum ENUM_ADD{
    a, // 默认0
    b, // 自动增长1
    c, // 2
}

// 枚举 - 字符串
enum ENUM_STRING{
    a = 'aaa', // 字符串枚举,固定值,没有自动增长功能
    b = 'bbb'


}
// 反射枚举
enum REVERSING_MAPPING{
    MONDAY,
    TUESDAY
}
console.log(REVERSING_MAPPING[0]) // 输出 字符串  'MONDAY'

// 常量枚举 - 会在编译后,直接声明变量,并且把最终值赋值给变量
const enum CONST_ENUM{// 因为默认是0-1-2排序,所以会直接把0和1给到值
    A,
    B
}
let constA = CONST_ENUM.A;
console.log(constA) // 0
console.log(CONST_ENUM.B) // 1 */
// 异构枚举
// enum ENUM_YIGOU {
//   Success = true, //有些版本可以用,但是用的比较少.
//   Failure = 0
// }


// & 是交叉类型,代表将两个类型合并在一起成为一个类型 
/* let yu : {name: string} & {sex: number};
yu = { // 必须俩对象的属性都要有, 比如name 和sex 都要有.
    name: 'tkf',
    sex: 1
}


// 接口的交叉类型 ,做合并处理.
interface aa{
    name: string
}
interface bb {
    sex :number
}
type cc = aa & bb; */











// 类型别名 - 其实就是定义一个类型, 便于复用. 和接口不同,接口是对象. 
// type alias
/* type myTypeAlias = string | number | boolean;
// 便于复用.
let a :myTypeAlias;
let b :myTypeAlias;



// 为原始类型创建别名
type ID = string | number;

// 为对象类型创建别名
type User = {
  name: string;
  age: number;
  email?: string; // 可选属性
};

// 为联合类型创建别名
type Status = "active" | "inactive" | "pending";

// 为函数类型创建别名
type Handler = (event: Event) => void; */



// 类型别名和接口的区别
// 特性:                       类型别名:                   接口:
// 语法:                       type T = { ... }            interface T { ... }
// 拓展方式:                   通过交叉类型（&）               通过 extends 关键字或声明合并	
// 能否定义原始类型:           能（如 type ID = string）       不能
// 能否定义联合或者交叉类型:   能（如 `type A = string | number`） 不能直接定义联合类型
// 重复定义:                   不允许（会报错）                允许（自动合并) *****这个合并,现在好像不行了

// 类型别名: 可以递归自己,树状结构
// 1. 引用自身（递归类型）
// 用于定义树形结构：

// 2.与typeof 一起使用
// const config = {
//   host: "localhost",
//   port: 3000
// };

// type Config = typeof config; // 自动推导类型



// 泛型 - 常见用法1
// interface T_fanxing{
//     name: string,
//     age: number
// }
// function fanxingFn<T> (params :T):T{
//     // 一般都是返回这个参数,当然这个函数里 会根据传入的参数,做一些逻辑处理
//     return params;
// }
// fanxingFn({
//         name: 't',
//         age: 1
//     })

// 泛型- 用法2 - 可添加拓展.
// type fanxinfg = {
//     name: string,
//     age : number
// }
// function fanxingFn2<T extends  fanxinfg> (param:T): T{
//     return {
//         ...param
//     }
// }

// fanxingFn2({
//     name:"tkf",
//     age: 19,
//     extra: 'info'
// })

// enum ENUM_TKV{
//     FIRST,
//     SECOND,
//     THREE
// }
// // 泛型 - 泛型值可以多个
// function fanxingFn3<T,K,V>(type,data:T|K|V):T|K|V{
//     if(type === ENUM_TKV.FIRST){
//         return data;
//     }else if(type === ENUM_TKV.SECOND){
//         return data;
//     } else if(type === ENUM_TKV.THREE){
//         return data;
//     } else {
//         return data;
//     }
// }

// 接口 使用泛型
// interface fanxingIntreface<T>{
//     name: string,
//     age: number,
//     extra: T
// }
// let a :fanxingIntreface<String> = {
//     name: 'tfk',
//     age: 1,
//     extra:"string"
// }
// let b :fanxingIntreface<number> = {
//     name: 'tfk',
//     age: 1,
//     extra: 333
// }

// 声明文件 .d.ts文件, 可以对第三方库或者现存js模块等进行类型检查.
// 1. 比如第三方模块导出一个函数 
// demo.js文件
export function sum(a,b){
    return a+b
}

// 2. 项目中引入,就要在声明模块里指定他的类型如何传参和返回值
// demo.d.ts文件
// import { sum } from '....xxxx'
// declare function sum(a:number,b:number):number;